package rtpengine

import (
	"common/rtpengine/media"
	"common/rtpengine/rtp"
	"common/util"
	"common/util/reuse"
	"errors"
	"net"
	"time"
)

// not safe for multi goroutine.
type TrackLocal struct {
	id       string // 需要支持自动生成..
	binding  SenderBinding
	laddr    string
	localUdp net.Conn

	sessionRtp *SessionRTP

	// for rtp pack, 需要封装下..
	packetizer rtp.Packetizer
	sequencer  rtp.Sequencer

	samples  uint32 // 采样时长.
	frequece uint32
}

func NewTrackLocal(name string, localAddress string) *TrackLocal {
	track := new(TrackLocal)

	track.id = name
	//sender.localIP = _localIP
	track.laddr = localAddress
	track.frequece = 25 // 默认一秒50帧.

	return track
}

// bind parameters.
func (t *TrackLocal) Bind(binding SenderBinding) {
	t.binding = binding

	if binding.Options.Sequence == 0 {
		t.sequencer = rtp.NewRandomSequencer()
	} else {
		t.sequencer = rtp.NewFixedSequencer(binding.Options.Sequence)
	}

	if binding.Options.Mtu == 0 {
		binding.Options.Mtu = rtpOutboundMTU
	}

	t.packetizer = rtp.NewPacketizer(binding.Options.Mtu, uint8(binding.PayloadType), uint32(binding.Options.Ssrc), uint32(binding.Options.Ts),
		binding.Payloader, t.sequencer)

}
func (t *TrackLocal) Close() error {
	return t.sessionRtp.Close()
}

// AcceptStream returns a stream to handle RTP for a single SSRC
func (t *TrackLocal) AcceptStream() (*ReadStreamRTP, uint32, error) {
	return t.sessionRtp.AcceptStream()
}

// start session
func (t *TrackLocal) StartSession(config Config) error {
	conn, err := reuse.Dial("udp", t.laddr, t.binding.RightAddr)
	if err != nil {
		return err
	}

	t.sessionRtp, err = NewSessionRTP(conn, &config)
	t.localUdp = conn
	return err
}

// start session
func (t *TrackLocal) StartSessionDirectly(conn net.Conn, config Config) (err error) {
	t.binding.RightAddr = conn.RemoteAddr().String()
	t.sessionRtp, err = NewSessionRTP(conn, &config)
	t.localUdp = conn
	return
}

// Samples, may be change anywhere.
func (t *TrackLocal) SetSamples(samples uint32) {
	t.samples = samples
}

func (t *TrackLocal) SetFrequence(frequece uint32) {
	if frequece <= 0 {
		return
	}
	t.frequece = frequece
}

// write Samples.
func (t *TrackLocal) WriteSample(sample media.Sample) error {
	p := t.packetizer
	if p == nil {
		return nil
	}

	// skip packets by the number of previously dropped packets
	// for timestamp 统一，packets扔掉后需要向前增加sequence保证udp包流程.
	for i := uint16(0); i < sample.PrevDroppedPackets; i++ {
		t.sequencer.NextSequenceNumber()
	}
	duaration := t.samples / t.frequece

	if sample.PrevDroppedPackets > 0 {
		p.(rtp.Packetizer).SkipSamples(duaration * uint32(sample.PrevDroppedPackets))
	}
	packets := p.(rtp.Packetizer).Packetize(sample.Data, duaration)
	packetsLen := len(packets)
	if packetsLen <= 0 {
		return errors.New("WriteSample: packet is nil. ")
	}

	var writeErrs []error
	writeStream, err := t.sessionRtp.OpenWriteStream()
	if err != nil {
		return err
	}

	// 特殊情况下加速作用.
	if packetsLen == 1 {
		p := packets[0]
		if _, err := writeStream.WriteRTP(&p.Header, p.Payload); err != nil {
			writeErrs = append(writeErrs, err)
		}
		return util.FlattenErrs(writeErrs)
	}

	// 支持多个包写入..
	// 增加ticker控制.
	tickerMilliCount := 1000 / t.frequece
	ticker := time.NewTicker(time.Millisecond * time.Duration(tickerMilliCount)) // 50ms default
	for index := 0; true; <-ticker.C {
		if index >= packetsLen {
			break
		}

		// 写入
		p := packets[index]
		if _, err := writeStream.WriteRTP(&p.Header, p.Payload); err != nil {
			writeErrs = append(writeErrs, err)
		}
		index++
	}
	//for _, p := range packets {
	//	// 写入
	//	if _, err := writeStream.WriteRTP(&p.Header, p.Payload); err != nil {
	//		writeErrs = append(writeErrs, err)
	//	}
	//}

	return util.FlattenErrs(writeErrs)
}
